﻿using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;

namespace RabbitMQClient
{
    class Program
    {
        static LimitService l = new LimitService(1000, 1);

        static void Main(string[] args)
        {
            var factory = new ConnectionFactory();
            factory.HostName = "192.168.1.26";
            factory.UserName = "guest";
            factory.Password = "guest";

            using (var connection = factory.CreateConnection())
            {
                using (var channel = connection.CreateModel())
                {
                    channel.QueueDeclare("kibaQueue", false, false, false, null);

                    /* 这里定义了一个消费者，用于消费服务器接受的消息
                     * C#开发需要注意下这里，在一些非面向对象和面向对象比较差的语言中，是非常重视这种设计模式的。
                     * 比如RabbitMQ使用了生产者与消费者模式，然后很多相关的使用文章都在拿这个生产者和消费者来表述。
                     * 但是，在C#里，生产者与消费者对我们而言，根本算不上一种设计模式，他就是一种最基础的代码编写规则。
                     * 所以，大家不要复杂的名词吓到，其实，并没那么复杂。
                     * 这里，其实就是定义一个EventingBasicConsumer类型的对象，然后该对象有个Received事件，
                     * 该事件会在服务接收到数据时触发。
                     */
                    var consumer = new EventingBasicConsumer(channel);//消费者
                    channel.BasicConsume("kibaQueue", true, consumer);//消费消息
                    consumer.Received += (model, ea) =>
                    {
                        var body = ea.Body.Span;
                        var message = Encoding.UTF8.GetString(body);
                    };
                }
            }
        }

        //限流组件,采用数组做为一个环
        class LimitService
        {
            //当前指针的位置
            int currentIndex = 0;
            //限制的时间的秒数，即：x秒允许多少请求
            int limitTimeSencond = 1;
            //请求环的容器数组
            DateTime?[] requestRing = null;
            //容器改变或者移动指针时候的锁
            object objLock = new object();

            public LimitService(int countPerSecond, int _limitTimeSencond)
            {
                requestRing = new DateTime?[countPerSecond];
                limitTimeSencond = _limitTimeSencond;
            }

            //程序是否可以继续
            public bool IsContinue()
            {
                lock (objLock)
                {
                    var currentNode = requestRing[currentIndex];
                    //如果当前节点的值加上设置的秒 超过当前时间，说明超过限制
                    if (currentNode != null && currentNode.Value.AddSeconds(limitTimeSencond) > DateTime.Now)
                    {
                        return false;
                    }
                    //当前节点设置为当前时间
                    requestRing[currentIndex] = DateTime.Now;
                    //指针移动一个位置
                    MoveNextIndex(ref currentIndex);
                }
                return true;
            }
            //改变每秒可以通过的请求数
            public bool ChangeCountPerSecond(int countPerSecond)
            {
                lock (objLock)
                {
                    requestRing = new DateTime?[countPerSecond];
                    currentIndex = 0;
                }
                return true;
            }

            //指针往前移动一个位置
            private void MoveNextIndex(ref int currentIndex)
            {
                if (currentIndex != requestRing.Length - 1)
                {
                    currentIndex = currentIndex + 1;
                }
                else
                {
                    currentIndex = 0;
                }
            }
        }
    }
}
